package dex.micros_gdc

import java.text.DateFormat;
import java.text.ParseException
import java.text.SimpleDateFormat

import grails.gorm.DetachedCriteria

import org.apache.commons.lang.time.FastDateFormat;
import org.springframework.dao.DataIntegrityViolationException

import dex.micros_gdc.common.SQLConstants

class TaskController {

	static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

	// Export service provided by Export plugin
	def exportService
	def grailsApplication  //inject GrailsApplication
	static DateFormat DF = new SimpleDateFormat("MM/dd/yyyy")

	def taskService

	def index() {
		redirect(action: "list", params: params)
	}

	def list(Integer max) {
		params.max = 1000

		def criteria = new DetachedCriteria(Task).build {
			eq("closedFlag", "N")

			if(params.projectName)
				eq('projectName', params.projectName)

			if(params.developer)
				eq('developer', params.developer)

			if(params.tester)
				eq('tester', params.tester)

			if(params.ts)
				eq('status', params.ts)

			if(params.dt)
				eq('documentType', params.dt)

			if(params.at)
				eq('actionType', params.at)

			if(params.findId) {
				def findId = params.findId
				if(findId.toString().toLowerCase().startsWith("fb"))
					eq("feedbackNumber", findId.toString().substring(2))
				else
					eq("activityNumber", findId)
			}

			if(params.sort) {
				order(params.sort, params?.order?: "desc")
			} else {
				order("projectName", "asc")
				order("receivedDate", "desc")
			}
		}

		def results = criteria.list(max:params.max)

		exportTasks(results)

		prepareFlashMessage()

		[taskInstanceList: results,
		 taskInstanceTotal: results.size(),
		 validProjects: taskService.getValidProjects(),
		 developers: taskService.getDevelopers(),
		 testers: taskService.getTesters(),
		 findId: params.findId]
	}

	def create() {
		params.dueDate = new Date()
		params.receivedDate = new Date()

		def taskInstance = new Task(params)
		taskInstance.id = taskService.getNextNewTaskId()

		taskInstance.status = 'Reviewing'
		def dueDate = DF.format(taskInstance.dueDate)
		def receivedDate = DF.format(taskInstance.receivedDate)

		[taskInstance: taskInstance,
		 testerResources: taskService.getTesters(),
		 developerResources: taskService.getDevelopers(),
		 projects: taskService.getProjects(),
		 dueDateTemp: dueDate,
		 receivedDateTemp:
		 receivedDate,
		 completedDateTemp: ""]
	}

	def save() {
		params.closedFlag = "N"
		params.dueDate = DF.parse(params.dueDateTemp)
		params.receivedDate = DF.parse(params.receivedDateTemp)

		if(params?.completedDateTemp) {
			params.completedDate = DF.parse(params.completedDateTemp)
		}
		def taskInstance = new Task(params)
		taskInstance.id = taskService.getNextNewTaskId()
		taskInstance.status = 'Reviewing'

		if(params.actionType == "E") {
			taskInstance.status = ""
			taskInstance.testByGDCFlag = "N"
		}

		if (!taskInstance.save(flush: true)) {
			render(view: "create", model: [taskInstance: taskInstance])
			return
		}

		flash.message = message(code: 'default.created.message', args: [
			message(code: 'task.label', default: 'Task'),
			taskInstance.id
		])

		updateTestcase(taskInstance.id)

		redirect(action: "show", id: taskInstance.id, params:params)
	}

	def show(Long id) {
		def s = params.ts

		def taskInstance = Task.get(id)
		if (!taskInstance) {
			flash.message = message(code: 'default.not.found.message', args: [
				message(code: 'task.label', default: 'Task'),
				id
			])
			redirect(action: "list")
			return
		}

		[taskInstance: taskInstance]
	}

	def edit(Long id) {
		def taskInstance = Task.get(id)
		if (!taskInstance) {
			flash.message = message(code: 'default.not.found.message', args: [
				message(code: 'task.label', default: 'Task'),
				id
			])
			redirect(action: "list")
			return
		}


		def dueDate = DF.format(taskInstance.dueDate)
		def receivedDate = DF.format(taskInstance.receivedDate)

		def completedDate = ""
		if(taskInstance?.completedDate){
			completedDate = DF.format(taskInstance.completedDate)
		}

		[taskInstance: taskInstance,
	     testerResources: taskService.getTesters(),
		 developerResources: taskService.getDevelopers(),
		 projects: taskService.getProjects(),
		 dueDateTemp: dueDate,
		 receivedDateTemp:
		 receivedDate,
		 completedDateTemp: completedDate]
	}

	def update(Long id, Long version) {
		params.dueDate = DF.parse(params.dueDateTemp)
		params.receivedDate = DF.parse(params.receivedDateTemp)

		if(params?.completedDateTemp) {
			params.completedDate = DF.parse(params.completedDateTemp)
		} else {
			params.completedDate = null
		}

		def taskInstance = Task.get(id)
		if (!taskInstance) {
			flash.message = message(code: 'default.not.found.message', args: [
				message(code: 'task.label', default: 'Task'),
				id
			])
			redirect(action: "list")
			return
		}

		if (version != null) {
			if (taskInstance.version > version) {
				taskInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
						[
							message(code: 'task.label', default: 'Task')] as Object[],
						"Another user has updated this Task while you were editing")
				render(view: "edit", model: [taskInstance: taskInstance])
				return
			}
		}

		taskInstance.properties = params

		if(params.actionType == "E") {
			taskInstance.status = ""
			taskInstance.testByGDCFlag = "N"
			taskInstance.rootCause = ""
		}

		if (!taskInstance.save(flush: true)) {
			render(view: "edit", model: [taskInstance: taskInstance])
			return
		}

		flash.message = message(code: 'default.updated.message', args: [
			message(code: 'task.label', default: 'Task'),
			taskInstance.id
		])

		updateTestcase(taskInstance.id)

		def projectName = params?.pN ?: ""
		def developer = params?.dev?: ""
		def tester = params?.qa ?: ""
		def status = params?.ts ?: ""
		def docType = params?.dt ?: ""
		def actionType = params?.at ?: ""

		redirect(action: "show",
			id: taskInstance.id,
			params: ["projectName": projectName, "developer": developer, "tester": tester, "ts": status, "dt":docType, "at":actionType])
	}

	def delete(Long id) {
		def taskInstance = Task.get(id)
		if (!taskInstance) {
			flash.message = message(code: 'default.not.found.message', args: [
				message(code: 'task.label', default: 'Task'),
				id
			])
			redirect(action: "list")
			return
		}

		try {
			deleteTestcase(taskInstance.id)
			taskInstance.delete(flush: true)

			flash.message = message(code: 'default.deleted.message', args: [
				message(code: 'task.label', default: 'Task'),
				id
			])


			redirect(action: "list")
		}
		catch (DataIntegrityViolationException e) {
			flash.message = message(code: 'default.not.deleted.message', args: [
				message(code: 'task.label', default: 'Task'),
				id
			])
			redirect(action: "show", id: id)
		}
	}

	def search()  {
		redirect(action: "list", params: params)
	}

	private def exportTasks(tasks){
		if(params?.format && params.format != "html"){
			response.contentType = grailsApplication.config.grails.mime.types[params.format]
			response.setHeader("Content-disposition", "attachment; filename=tasks.${params.extension}")

			List fields = [
				"projectName",
				"activityNumber",
				"feedbackNumber",
				"receivedDate",
				"dueDate",
				"completedDate",
				"actionType",
				"documentType",
				"status",
				"risk",
				"ptsHour",
				"estimateHour",
				"rootCause",
				"developer",
				"tester",
				"testByGDCFlag",
				"comments",
				"closedFlag"
			]

			Map labels = [
				"projectName":"Project Name",
				"activityNumber": "Activity #",
				"feedbackNumber": "FB #",
				"receivedDate":"Received Date",
				"dueDate": "Due Date",
				"completedDate": "Completed Date",
				"actionType": "Action Type",
				"documentType":"Doc Type",
				"status":"Status",
				"risk": "Risk",
				"ptsHour":"PTS",
				"estimateHour":"GDC",
				"rootCause":"Root Cause",
				"developer" :"DEV",
				"tester":"QA",
				"testByGDCFlag":"GDC QA",
				"comments":"Comments",
				"closedFlag":"Closed?"]

			Map parameters = ["column.widths": [
					0.15,
					0.12,
					0.12,
					0.15,
					0.15,
					0.15,
					0.10,
					0.10,
					0.20,
					0.10,
					0.10,
					0.10,
					0.25,
					0.20,
					0.20,
					0.15,
					0.50,
					0.10
				]]
			exportService.export(params.format, response.outputStream, tasks, fields, labels, [:], parameters)
		}
	}

	private def getNewTaskInfo(){
		def tasks = taskService.getTodayReceivedTasks()

		return populateTaskInfo(tasks)
	}

	private String populateTaskInfo(tasks) {
		def taskInfo = ""

		for (i in 0..<tasks.size()) {
			if(taskInfo.empty) {
				taskInfo = message(code: 'new.task.message', args: [
					tasks[i][0],
					tasks[i][1]
				])

			}else {
				taskInfo = taskInfo + "  --  " + message(code: 'new.task.message', args: [
					tasks[i][0],
					tasks[i][1]
				])}
		}

		return taskInfo
	}

	private def prepareFlashMessage() {
		def newTaskInfo = getNewTaskInfo()

		if(newTaskInfo) {
			flash.message = message(code: 'new.messsage', args: [newTaskInfo])
		}
		else {
			flash.message = ""
		}
	}

	private def updateTestcase(taskId){
		def task = Task.get(taskId)

		if(task != null && "TDD".equals(task.documentType)) {
			def testcase = Testcase.get(taskId)

			def chagnedFieldsMap = testcaseChangedFields(task)

			if(testcase != null) {
				testcase.properties = chagnedFieldsMap
			} else {
				testcase = new Testcase(chagnedFieldsMap)
				testcase.testcaseStatus = 'In Progress'
				testcase.id = taskId
			}

			testcase.save(flush:true)
		} else {
			deleteTestcase(taskId)
		}
	}

	private def deleteTestcase(id) {
		def testcase = Testcase.get(id)

		if(testcase != null){
			testcase.delete(flush:true)
		}
	}

	private def testcaseChangedFields(Task task) {
		def map = ["projectName": task.projectName,
			"receivedDate":task.receivedDate,
			"activityNumber": task.activityNumber,
			"status":task.status,
			"dueDate":task.dueDate,
			"delivered": 'N']

		return map
	}
}
